<html>
<head>
  <title>asyncio（异步编程）</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="Evernote Windows/307027 (zh-CN, DDL); Windows/6.1.0 (Win32);"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 10pt;
    }
  </style>
</head>
<body>
<a name="619"/>
<h1>asyncio（异步编程）</h1>

<div>
<span><div><div><a href="https://docs.python.org/3/library/asyncio.html">https://docs.python.org/3/library/asyncio.html</a></div><h1><a href="https://docs.python.org/3/library/asyncio.html#module-asyncio" style="font-size: 16pt; font-weight: normal;" title="asyncio: Asynchronous I/O, event loop, coroutines and tasks.">asyncio</a> <span style="font-size: 16pt; font-weight: normal;">— Asynchronous I/O, event loop, coroutines and tasks</span></h1><div><font style="font-size: 18pt;"><span style="color: rgb(28, 51, 135); font-size: 18pt; font-weight: bold;">什么是异步</span></font></div><div><br/></div><div>        因为一个IO操作就阻塞了当前线程，导致其他代码无法执行，所以我们必须使用多线程或者多进程来并发执行代码，为多个用户服务。每个用户都会分配一个线程，如果遇到IO导致线程被挂起，其他用户的线程不受影响。</div><div>        多线程和多进程的模型虽然解决了并发问题，但是系统不能无上限地增加线程。由于系统切换线程的开销也很大，所以，一旦线程数量过多，CPU的时间就花在线程切换上了，真正运行代码的时间就少了，结果导致性能严重下降。</div><div><font style="font-size: 12pt;"><span style="color: rgb(227, 0, 0); font-size: 12pt; font-weight: bold;">另一种解决IO问题的方法是异步IO。当代码需要执行一个耗时的IO操作时，它只发出IO指令，并不等待IO结果，然后就去执行其他代码了。一段时间后，当IO返回结果时，再通知CPU进行处理。</span></font></div><div><br/></div><div><br/></div><div><br/></div><div><font style="font-size: 18pt;"><span style="color: rgb(28, 51, 135); font-size: 18pt; font-weight: bold;">问题</span></font></div><div>如果按普通顺序写出的代码实际上是没法完成异步IO的：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">do_some_code()</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">f = open('/path/to/file', 'r')</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">r = f.read() # &lt;== </span><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">线程停在此处等待IO操作结果\</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;"># <span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">IO操作完成后线程才能继续执行</span></span></div><div><span style="font-size: 9pt;"><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">do_some_code(r)</span></span></div></div><div>所以，同步IO模型的代码是无法实现异步IO模型的。</div><div><br/></div><div><font style="font-size: 14pt;"><span style="color: rgb(50, 135, 18); font-size: 14pt; font-weight: bold;">通用模型：消息循环</span></font></div><div><font style="font-size: 14pt;"><span style="color: rgb(50, 135, 18); font-size: 14pt; font-weight: bold;">主线程不断重复：读取消息-处理消息</span></font></div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); color: rgb(50, 135, 18); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 14pt;">loop = get_event_loop()</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(50, 135, 18); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 14pt;">while True:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(50, 135, 18); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 14pt;">    event = loop.get_event()</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(50, 135, 18); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 14pt;">    process_event(event)</span></div></div><div><br/></div><div>消息模型其实早在应用在桌面应用程序中了。一个GUI程序的主线程就负责不停地读取消息并处理消息。所有的键盘、鼠标等消息都被发送到GUI程序的消息队列中，然后由GUI程序的主线程处理。</div><div><br/></div><div>在“发出IO请求”到收到“IO完成”的这段时间里，同步IO模型下，主线程只能挂起，但异步IO模型下，主线程并没有休息，而是在消息循环中继续处理其他消息。这样，在异步IO模型下，一个线程就可以同时处理多个IO请求，并且没有切换线程的操作。对于大多数IO密集型的应用程序，使用异步IO将大大提升系统的多任务处理能力。</div><div><br/></div><div><br/></div><h2><span style="font-size: 18pt; color: rgb(28, 51, 135);">什么是协程</span><span style="font-size: 18pt; color: rgb(28, 51, 135); font-weight: bold;">(coroutine)</span></h2><div>协程，又称微线程，纤程。英文名Coroutine。</div><div><br/></div><div>子程序，或者称为函数，在所有语言中都是层级调用，比如A调用B，B在执行过程中又调用了C，C执行完毕返回，B执行完毕返回，最后是A执行完毕。<span style="line-height: 1.45;">所以子程序调用是通过栈实现的，一个线程就是执行一个子程序。</span><span style="line-height: 1.45;">子程序调用总是一个入口，一次返回，调用顺序是明确的。</span></div><div><br/></div><div>而协程的调用和子程序不同。</div><div><font style="font-size: 12pt;"><span style="color: rgb(227, 0, 0); font-size: 12pt; font-weight: bold;">协程看上去也是子程序，但执行过程中，在子程序内部可中断</span></font>，然后转而执行别的子程序，在适当的时候再返回来接着执行。</div><div>注意，在一个子程序中中断，去执行其他子程序，不是函数调用，有点类似CPU的中断。例如：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">def A():</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    print('1')</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    print('2')</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    print('3')</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">def B():</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    print('x')</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    print('y')</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    print('z')</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">假设由协程执行，在执行A的过程中，可以随时中断，去执行B，B也可能在执行过程中中断再去执行A，结果可能是：</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">1</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">2</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">x</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">y</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">3</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">z</span></div></div><div><font color="#E30000" style="font-size: 12pt;"><span style="color: rgb(227, 0, 0); font-size: 12pt; font-weight: bold;">但是在A中是没有调用B的，所以协程的调用比函数调用理解起来要难一些。</span></font></div><div><br/></div><div><br/></div><div><font style="font-size: 18pt;"><span style="color: rgb(28, 51, 135); font-size: 18pt; font-weight: bold;">协程的优势</span></font></div><div>最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换，而是由程序自身控制，因此，没有线程切换的开销，和多线程比，线程数量越多，协程的性能优势就越明显。</div><div><br/></div><div>第二大优势就是不需要多线程的锁机制，因为只有一个线程，也不存在同时写变量冲突，在协程中控制共享资源不加锁，只需要判断状态就好了，所以执行效率比多线程高很多。</div><div><br/></div><div>因为协程是一个线程执行，那怎么利用多核CPU呢？最简单的方法是多进程+协程，既充分利用多核，又充分发挥协程的高效率，可获得极高的性能。</div><div><br/></div><div><br/></div><div><br/></div><div><font style="font-size: 18pt;"><span style="color: rgb(28, 51, 135); font-size: 18pt; font-weight: bold;">Python对协程的支持</span></font></div><div><br/></div><div>Python对协程的支持是通过generator实现的。</div><div>在generator中，我们不但可以通过for循环来迭代，还可以不断调用next()函数获取由yield语句返回的下一个值。</div><div><font style="font-size: 12pt;"><span style="color: rgb(227, 0, 0); font-size: 12pt; font-weight: bold;">yield：</span><span style="font-size: 12pt; color: rgb(227, 0, 0); font-weight: bold;">Python的yield不但可以返回一个值，它还可以接收调用者发出的参数。</span></font></div><div>如果改用协程，生产者生产消息后，直接通过yield跳转到消费者开始执行，待消费者执行完毕后，切换回生产者继续生产，效率极高：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">def consumer():</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    r = ''</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    while True:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        n = yield r</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        if not n:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">            return</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        print('[CONSUMER] Consuming %s...' %n)</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        r = '200 0k'</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">def produce(c):</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    c.send(None)</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    n = 0</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    while n &lt; 5:</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        n = n + 1</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        print('[PRODUCER] Producing %s...' %n)</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        r = c.send(n)</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">        print('[PRODUCER] Consumer return: %s' %r)</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    c.close()</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">c = consumer()</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">produce(c)</span></div><div><br/></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">执行结果：</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[PRODUCER] Producing 1...</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[CONSUMER] Consuming 1...</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[PRODUCER] Consumer return: 200 OK</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[PRODUCER] Producing 2...</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[CONSUMER] Consuming 2...</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[PRODUCER] Consumer return: 200 OK</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[PRODUCER] Producing 3...</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[CONSUMER] Consuming 3...</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[PRODUCER] Consumer return: 200 OK</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[PRODUCER] Producing 4...</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[CONSUMER] Consuming 4...</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[PRODUCER] Consumer return: 200 OK</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[PRODUCER] Producing 5...</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[CONSUMER] Consuming 5...</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">[PRODUCER] Consumer return: 200 OK</span></div></div><div>注意到consumer函数是一个generator，把一个consumer传入produce后：</div><ol><li>首先调用c.send(None)启动生成器；</li><li>然后，一旦生产了东西，通过c.send(n)切换到consumer执行；</li><li>consumer通过yield拿到消息，处理，又通过yield把结果传回；</li><li>produce拿到consumer处理的结果，继续生产下一条消息；</li><li>produce决定不生产了，通过c.close()关闭consumer，整个过程结束。</li></ol><div style="margin-top: 1em; margin-bottom: 1em;">整个流程无锁，由一个线程执行，produce和consumer协作完成任务，所以称为“协程”，而非线程的抢占式多任务。</div><div style="margin-top: 1em; margin-bottom: 1em;">最后套用Donald Knuth的一句话总结协程的特点：<span style="line-height: 1.45;">“子程序就是协程的一种特例。”</span></div><div><br/></div><div><br/></div><h4><span style="color: rgb(28, 51, 135); font-size: 18pt;">asyncio</span></h4><div>asyncio的编程模型就是一个消息循环。我们从asyncio模块中直接获取一个EventLoop</div><div>的引用，然后把需要执行的协程扔到EventLoop中执行，就实现了异步IO。</div><div>用asyncio实现Hello world代码如下：</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">import asyncio</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">@asyncio.coroutine</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">def hello():</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    print(&quot;Hello world!&quot;)</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    # 异步调用 asyncio.sleep(1)</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    r = yield from asyncio.sleep(1)</span></div><div><span style="background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 12px;">    print(&quot;Hello again!&quot;)</span></div><div><br/></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;"># 获取EventLoop:</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">loop = asyncio.get_event_loop()</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;"># 执行coroutine</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">loop.run_until_complete(hello())</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">loop.close()</span></div></div><div><font style="font-size: 14pt; color: rgb(50, 135, 18);"><b>分析：</b></font></div><div><ol><li>yield 吧一个函数变为generator（生成器）</li><li>@asyncio.coroutine把一个generator标记为coroutine类型</li><li>把这个coroutine 放到EventLoop中执行</li><li>『『hello() 先打印出Hello world！， yield from 语法可以让我们方便的调用另一个coroutine , 即 asyncio.sleep()。由于asyncio.sleep() 也是一个协程，所以线程也不会等待sleep(),  而是直接终端去并执行下一个消息循环。  当asyncio.sleep() 返回时， 线程就可以从 yield from 拿到返回值（此处是None），然后执行下一行语句。』<span style="line-height: 1.45;">』</span></li><li><span style="line-height: 1.45;">把asyncio.sleep(1) 看成是一个耗时1秒的IO操作， 在此期间，主线程并未等待，而是去执行EventLoop中其他可以执行的coroutine了。</span></li></ol><div><br/></div></div><div><font style="font-size: 16pt; color: rgb(173, 0, 0);"><b>例： 用Task封装两个coroutine试试：</b></font></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>import threading</div><div>import asyncio</div><div><br/></div><div>@asyncio.coroutine</div><div>def hello():</div><div><span>    print('Hello world! (%s)' % threading.currentThread())</span><br/></div><div><span><span>    yield from asyncio.sleep(1)</span><br/></span></div><div><span><span>    print('Hello again! (%s)' % threading.currentThread())</span><br/></span></div><div><span><br/></span></div><div><span>loop = asyncio.get_event_loop()</span></div><div><span>tasks = [hello(), hello()]</span></div><div><span>loop.run_until_complete(asyncio.wait(tasks))</span></div><div><span>loop.close()</span></div></div><div><font style="font-size: 14pt; color: rgb(50, 135, 18);"><b>分析：</b></font></div><div><ol><li>tasks列表创建了两个协程</li><li>两个协程coroutine 是由一个线程并发执行</li><li>sleep的时间到了后，该协程会通知主线程回到该协程继续执行。</li></ol></div><div><br/></div><div>例子：用asyncio 的异步网络连接来获取sina、sohu和 163的网站首页：</div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">import asyncio</span></div><div><br style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"/></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">@asyncio.coroutine</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">def wget(host):</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    </span>print('wget %s...' % host)</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    </span>connect = asyncio.open_connection(host, 80)</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    </span>reader, writer = yield from connect</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    </span>header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    </span>writer.write(header.encode('utf-8'))</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    </span>yield from writer.drain()</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    </span>while True:</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    <span>    </span></span>line = yield from reader.readline()</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    <span>    </span></span>if line == b'\r\n':</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    <span>    <span>    </span></span></span>break</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    <span>    </span></span>print('%s header &gt; %s' % (host, line.decode('utf-8').rstrip()))</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    </span># Ignore the body, close the socket</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    </span>writer.close()</span></div><div><br style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"/></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">loop = asyncio.get_event_loop()</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">tasks = [wget(host) for host in ['</span><a href="http://www.sina.com.cn'/" style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">www.sina.com.cn'</a><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">;, '</span><a href="http://www.sohu.com'/" style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">www.sohu.com'</a><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">;, '</span><a href="http://www.163.com'/" style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">www.163.com'</a><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">;]]</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">loop.run_until_complete(asyncio.wait(tasks))</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">loop.close()<span>    </span></span></div></div><h3><br/></h3><h3><font style="font-size: 18pt; color: rgb(28, 51, 135);">async/await</font></h3><div>用asyncio提供的@asyncio.coroutine可以把一个generator标记为coroutine类型，然后在coroutine内部用yield from调用另一个coroutine实现异步操作。</div><div>为了简化并更好地标识异步IO，从Python 3.5开始引入了<font style="font-size: 12pt; color: rgb(173, 0, 0);"><b>新的语法async和await</b></font>，可以让coroutine的代码更简洁易读。</div><div><span style="line-height: 1.45;"><font style="font-size: 14pt; color: rgb(173, 0, 0);"><b>只需两步替换：</b></font></span></div><div><ol><li><font color="#AD0000"><span style="font-size: 19px; line-height: 27px;"><b>把@asyncio.coroutine 替换为async</b></span></font></li><li><font color="#AD0000"><span style="font-size: 19px; line-height: 27px;"><b>把yield from 替换为await。</b></span></font></li></ol></div><div>k</div><h3><span style="line-height: 1.45;">example1</span><br/></h3><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">&gt;&gt;&gt; def coroutine():</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">...          reply = yield 'hello'</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">...         </span><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco; line-height: 1.45;"> yield reply</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">...</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">&gt;&gt;&gt; c = coroutine()</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">&gt;&gt;&gt; next(c)</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">'hello'</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">&gt;&gt;&gt; c.send('world')</span></div><div><span style="font-size: 9pt; background-color: rgb(251, 250, 248); color: rgb(51, 51, 51); font-family: Monaco;">'world</span></div></div><h3>example2</h3><div>功能：模拟多个学生同时向一个老师提交作业</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">from collections import deque</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def student(name, homeworks):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    for homework in homeworks.items():</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        yield (name, homework[0], homework[1])  # 学生“生成”作业给老师</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">class Teacher(object):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    def __init__(self, students):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        self.students = deque(students)</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    def handle(self):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        &quot;&quot;&quot;老师处理学生作业&quot;&quot;&quot;</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        while len(self.students):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">            student = self.students.pop()</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">            try:</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">                homework = next(student)</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">                print('handing', homework[0], homework[1], homework[2])</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">            except StopIteration:</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">                pass</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">            else:</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">                self.students.appendleft(student)</span></div></div><div>下面我们来调用一下这个程序。</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">Teacher([</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    student('Student1', {'math': '1+1=2', 'cs': 'operating system'}),</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    student('Student2', {'math': '2+2=4', 'cs': 'computer graphics'}),</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    student('Student3', {'math': '3+3=5', 'cs': 'compiler construction'})</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">]).handle()</span></div></div><div style="margin-top: 1em; margin-bottom: 1em;">这是输出结果，我们仅仅只用了一个简单的生成器就实现了并发(concurrence)，注意不是并行(parallel)，因为我们的程序仅仅是运行在一个单线程当中。</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">handling Student3 cs compiler construction</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">handling Student2 cs computer graphics</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">handling Student1 cs operating system</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">handling Student3 math 3+3=5</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">handling Student2 math 2+2=4</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">handling Student1 math 1+1=2</span></div></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div>使用asyncio模块实现协程</div><div>解释：下面代码中，我们自己定义了一个协程 display_date(num, loop) ，然后它使用关键字yield from 来等待协程 asyncio.sleep(2) 的返回结果。而在这等待的2s 之间它会让出CPU 的执行权， 知道asyncio.sleep(2) 返回结果。gather() 或者wait() 来返回future的执行结果。</div><div style="box-sizing: border-box; padding: 8px; font-size: 12px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902);"><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;"># coroutine.py</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">import asyncio</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">import datetime</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">@asyncio.coroutine # 声明一个协程</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">#async def display_date(num, loop)</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">def display_date(num, loop):</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    end_time = loop.time() + 10.0</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">    while True:</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        print(&quot;Loop: {} Time: {}&quot;.format(num,datetime.datetime.now()))</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">        if (loop.time() + 1.0) &gt;= end_time:</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">            break</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">       </span> <font style="font-size: 12pt;"><span style="background-color: rgb(251, 250, 248); font-size: 12pt; color: rgb(173, 0, 0); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-weight: bold;">yield from asyncio.sleep(2)  #阻塞直到协程sleep(2)返回结果# await asyncio.sleep(2)</span></font></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">loop = asyncio.get_event_loop() # 获取一个event_loop</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">tasks = [display_date(1, loop), display_date(2, loop)]</span></div><div><br/></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">loop.run_until_comlete(asyncio.gather(*tasks)) # 阻塞直到所有的tasks完成</span></div><div><span style="background-color: rgb(251, 250, 248); font-size: 12px; color: rgb(51, 51, 51); font-family: Monaco, Menlo, Consolas, 'Courier New', monospace;">loop.close()</span></div></div><div><br/></div><div>在Python3.5中为我们提供更直接的对协程的支持，引入了async/await关键字，上面的代码我们可以这样改写，使用async代替了@asyncio.coroutine，使用了await代替了yield from，这样我们的代码变得更加简洁可读。</div><div><br/></div><div><br/></div><div><br/></div><div><div><br/></div><table style="border-collapse: collapse; min-width: 100%;"><colgroup><col style="width: 272px;"></col><col style="width: 290px;"></col></colgroup><tbody><tr><td style="border: 1px solid rgb(204, 204, 204); width: 272px; padding: 8px;"><div>run_until_complete()</div></td><td style="border: 1px solid rgb(204, 204, 204); width: 290px; padding: 8px;"><div>开启事件循环</div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 272px; padding: 8px;"><div><span style="font-size: 11pt;">run_forever()</span></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 290px; padding: 8px;"><div>开启事件循环</div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 272px; padding: 8px;"><div><span style="font-weight: bold;">call_soon()</span></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 290px; padding: 8px;"><div>提前注册我们的task</div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 272px; padding: 8px;"><div><span style="font-weight: bold;">call_later()</span></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 290px; padding: 8px;"><div>loop.call_later(1, display_date, end_time, loop)</div></td></tr><tr><td style="border: 1px solid rgb(204, 204, 204); width: 272px; padding: 8px;"><div><br/></div></td><td style="border: 1px solid rgb(204, 204, 204); width: 290px; padding: 8px;"><div><br/></div></td></tr></tbody></table><div><br/></div></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div style="text-align: center;"><font style="font-size: 24pt; color: rgb(28, 51, 135);"><b>aiohttp</b></font></div><div><br/></div><div><span style="-en-paragraph: true;">如果把</span><span style="-en-paragraph: true;">asyncio</span><span style="-en-paragraph: true;">用在服务器端，例如Web服务器，由于HTTP连接就是IO操作，因此可以用单线程+</span><span style="-en-paragraph: true;">coroutine</span><span style="-en-paragraph: true;">实现多用户的高并发支持。</span></div><div><span style="-en-paragraph: true;">asyncio</span><span style="-en-paragraph: true;">实现了TCP、UDP、SSL等协议，</span><span style="-en-paragraph: true;">aiohttp</span><span style="-en-paragraph: true;">则是基于</span><span style="-en-paragraph: true;">asyncio</span><span style="-en-paragraph: true;">实现的HTTP框架。</span></div><div><span style="-en-paragraph: true;">安装：</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div><span style="-en-paragraph: true; font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">pip install aiohttp</span></div></div><div><span style="-en-paragraph: true;">然后编写一个HTTP服务器，分别处理以下URL：</span></div><ul><li><span style="-en-paragraph: true;">/</span> <span style="-en-paragraph: true;">- 首页返回</span><span style="-en-paragraph: true;">b'&lt;h1&gt;Index&lt;/h1&gt;'</span><span style="-en-paragraph: true;">；</span></li><li><span style="-en-paragraph: true;">/hello/{name}</span> <span style="-en-paragraph: true;">- 根据URL参数返回文本</span><span style="-en-paragraph: true;">hello, %s!</span><span style="-en-paragraph: true;">。</span></li></ul><div><span style="-en-paragraph: true;">代码如下：</span></div><div style="box-sizing: border-box; padding: 8px; font-family: Monaco, Menlo, Consolas, &quot;Courier New&quot;, monospace; font-size: 12px; color: rgb(51, 51, 51); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; background-color: rgb(251, 250, 248); border: 1px solid rgba(0, 0, 0, 0.14902); background-position: initial initial; background-repeat: initial initial;-en-codeblock:true;"><div>import asyncio</div><div><br/></div><div>from aiohttp import web</div><div><br/></div><div>async def index(request):</div><div><span>    await asyncio.sleep(0.5)</span><br/></div><div><span><span>    return web.Response(body=b'&lt;h1&gt;Index&lt;/h1&gt;')</span><br/></span></div><div><span><br/></span></div><div>async def hello(request):</div><div><span>    await asyncio.sleep(0.5)</span><br/></div><div><span>    <span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">text = '&lt;h1&gt;hello, %s!&lt;/h1&gt;' % request.match_info['name']</span></span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    <span>  </span></span> return web.Response(body=text.encode('utf-8'))</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><br/></span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);">async def init(loop):</span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    <span>   app = web.Application(loop=loop)</span></span><br/></span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span><span>    <span>   app.router.add_route('GET', '/', index)</span></span><br/></span></span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span><span>    <span>   app.router.add_route('GET', '/hello/{name}', hello)</span></span><br/></span></span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span><span>    <span>   srv = await loop.create_server(app,make_handler(), '127.0.0.1', 8000)</span></span><br/></span></span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span><span>    <span>   print(' Server started at <a href="http://127.0.0.1:8000...')/">http://127.0.0.1:8000...')</a></span></span><br/></span></span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>    <span>   return srv</span></span></span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span><br/></span></span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>loop = asyncio.get_event_loop()</span></span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>loop = run_until_complete(init(loop))</span></span></div><div><span style="font-family: Monaco; font-size: 9pt; color: rgb(51, 51, 51);"><span>loop.run_forever()</span></span></div></div><div>注意aiohttp的初始化函数init()也是一个coroutine，loop.create_server()则利用asyncio创建TCP服务。</div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div><div><br/></div></div><div><br/></div></span>
</div></body></html> 